//
//  lm_conf_voice_wrapper.m
//  LMConf_ios
//
//  Created by lh Authors on 16/6/19.
//  Copyright © 2016 lh. All rights reserved.
//

#import "lm_conf_voice_wrapper.h"

void CALLBACK FuncVoiceOnDisconnectVoiceServerCB(
                                                 int result, void* clientdata) {
    ConfVoiceWrapper* wrapper = (__bridge ConfVoiceWrapper*)(clientdata);
    for(id obj in [wrapper delegate_array]) {
        id<ConfVoiceWrapperDelegate> delegate = obj;
        if([delegate respondsToSelector:@selector(onDisconnectVoiceServer:)]) {
            [delegate onDisconnectVoiceServer:result];
        }
    }
}

void CALLBACK FuncVoiceOnDeviceChangeCB(void* clientdata) {
    ConfVoiceWrapper* wrapper = (__bridge ConfVoiceWrapper*)(clientdata);
    for(id obj in [wrapper delegate_array]) {
        id<ConfVoiceWrapperDelegate> delegate = obj;
        if([delegate respondsToSelector:@selector(onDeviceChange)]) {
            [delegate onDeviceChange];
        }
    }
}

@implementation ConfVoiceWrapper

@synthesize delegate_array = delegate_array_;

- (id)init {
    if ((self = [super init])) {
        c_object_ = NULL;
        delegate_array_ = [[NSMutableArray alloc] init];
    }
    return self;
}

- (id)initWithCObject:(native_object_t)c_object {
    if ((self = [super init])) {
        c_object_ = c_object;
        delegate_array_ = [[NSMutableArray alloc] init];
    
        struct ConfVoiceCallback cb;
        memset(&cb, 0, sizeof(cb));
        cb.client_data_ = (__bridge void*)self;
        cb.OnDeviceChange_ = FuncVoiceOnDeviceChangeCB;
        cb.OnDisconnectVoiceServer_ = FuncVoiceOnDisconnectVoiceServerCB;
        lm_conf_voice_set_callback(c_object_, &cb);
    }
    return self;
}

- (void)addDelegate:(id<ConfVoiceWrapperDelegate>)voice_delegate {
    [delegate_array_ addObject:voice_delegate];
}

- (void)removeDelegate:(id<ConfVoiceWrapperDelegate>)voice_delegate {
    [delegate_array_ removeObject:voice_delegate];
}

- (int)setCodecType:(enum LMVoiceCodecModes)codec_type
          delayMode:(enum LMVoiceDelayModes)delay_mode {    
    return lm_conf_voice_SetCodecType(c_object_, codec_type, delay_mode);
}

- (int)getCodecType:(enum LMVoiceCodecModes*)codec_type
          delayMode:(enum LMVoiceDelayModes*)delay_mode {
    return lm_conf_voice_GetCodecType(c_object_, (int*)(codec_type), (int*)(delay_mode));
}

- (int)setCodecTypeWithInputDevice:(enum LMVoiceDeviceType)input_type
                         codecType:(enum LMVoiceCodecModes)codec_type
                         delayMode:(enum LMVoiceDelayModes)delay_mode
                              rate:(int)rate {
    return lm_conf_voice_SetCodecTypeWithInputDevice(c_object_, input_type,codec_type, delay_mode, rate);
}

- (int)getCodecTypeWithInputDevice:(enum LMVoiceDeviceType)input_type
                         codecType:(enum LMVoiceCodecModes*)codec_type
                         delayMode:(enum LMVoiceDelayModes*)delay_mode
                              rate:(int*)rate {
    return lm_conf_voice_GetCodecTypeWithInputDevice(c_object_, input_type,
                                                     (int*)codec_type, (int*)delay_mode, rate);
}

- (BOOL)isValidDelayMode:(enum LMVoiceCodecModes)codec_type
               delayMode:(enum LMVoiceDelayModes)delay_mode {
    return !!lm_conf_voice_IsValidDelayMode(c_object_, codec_type, delay_mode);
}

- (int)getNumOfInputDevices:(int *)nums {
    return lm_conf_voice_GetNumOfInputDevices(c_object_, nums);
}

- (int)getNumOfOutputDevices:(int *)nums {
    return lm_conf_voice_GetNumOfOutputDevices(c_object_, nums);
}

- (int)getInputDeviceName:(int)index
                     name:(char *)name
                 name_len:(int)name_len
                     guid:(char *)guid
                 guid_len:(int)guid_len {
    return lm_conf_voice_GetInputDeviceName(c_object_, index, name, name_len, guid, guid_len);
}

- (int)getOutputDeviceName:(int)index
                      name:(char *)name
                  name_len:(int)name_len
                      guid:(char *)guid
                  guid_len:(int)guid_len {
    return lm_conf_voice_GetOutputDeviceName(c_object_, index, name, name_len, guid, guid_len);
}

- (int)getDefaultInputDeviceName:(char *)name
                        name_len:(int)name_len
                            guid:(char *)guid
                        guid_len:(int)guid_len {
    return lm_conf_voice_GetDefaultInputDeviceName(c_object_, name, name_len, guid, guid_len);
}

- (int)getDefaultOutputDeviceName:(char *)name
                         name_len:(int)name_len
                             guid:(char *)guid
                         guid_len:(int)guid_len {
    return lm_conf_voice_GetDefaultOutputDeviceName(c_object_, name, name_len, guid, guid_len);
}

- (int)getCurrentInputDeviceName:(char *)name
                        name_len:(int)name_len
                            guid:(char *)guid
                        guid_len:(int)guid_len {
    return lm_conf_voice_GetCurrentInputDeviceName(c_object_, name, name_len, guid, guid_len);
}

- (int)getCurrentOutputDeviceName:(char *)name
                         name_len:(int)name_len
                             guid:(char *)guid
                         guid_len:(int)guid_len {
    return lm_conf_voice_GetCurrentOutputDeviceName(c_object_, name, name_len, guid, guid_len);
}

- (int)getDefaultInputDeviceIndex:(int* )index {
    return lm_conf_voice_GetDefaultInputDeviceIndex(c_object_, index);
}

- (int)getDefaultOutputDeviceIndex:(int* )index {
    return lm_conf_voice_GetDefaultOutputDeviceIndex(c_object_, index);
}

- (int)getCurrentInputDeviceIndex:(int* )index {
    return lm_conf_voice_GetCurrentInputDeviceIndex(c_object_, index);
}

- (int)getCurrentOutputDeviceIndex:(int* )index {
    return lm_conf_voice_GetCurrentOutputDeviceIndex(c_object_, index);
}

- (int)setInputDevice:(int)index {
    return lm_conf_voice_SetInputDevice(c_object_, index);
}

- (int)setOutputDevice:(int)index {
    return lm_conf_voice_SetOutputDevice(c_object_, index);
}

- (int)setInputVolume:(unsigned int)volume {
    return lm_conf_voice_SetInputVolume(c_object_, volume);
}

- (int)getInputVolume:(unsigned int *)volume {
    return lm_conf_voice_GetInputVolume(c_object_, volume);
}

- (int)setOutputVolume:(unsigned int)volume {
    return lm_conf_voice_SetOutputVolume(c_object_, volume);
}

- (int)getOutputVolume:(unsigned int *)volume {
    return lm_conf_voice_GetOutputVolume(c_object_, volume);
}

- (int)getInputVoiceLevel:(unsigned int *)level {
    return lm_conf_voice_GetInputVoiceLevel(c_object_, level);
}

- (int)getOutputVoiceLevelForAccount:(NSString *)account
                               level:(unsigned int *)level {
    return lm_conf_voice_GetOutputVoiceLevel(c_object_, [account UTF8String], level);
}

- (int)getOutputVoiceLevel:(int)node level:(unsigned int *)level {
    return lm_conf_voice_GetOutputVoiceLevelWithNode(c_object_, node, level);
}

- (int)setLoudspeakerStatus:(BOOL)enabled {
    return lm_conf_voice_SetLoudspeakerStatus(c_object_, enabled ? 1 : 0);
}

- (int)setEcStatus:(BOOL)enabled
              mode:(enum LMEcModes)mode {
    return lm_conf_voice_SetEcStatus(c_object_, enabled ? 1 : 0, mode);
}

- (int)setNsStatus:(BOOL)enabled
              mode:(enum LMNsModes)mode {
    return lm_conf_voice_SetNsStatus(c_object_, enabled ? 1 : 0, mode);
}

- (int)setAgcStatus:(BOOL)enabled
               mode:(enum LMAgcModes)mode; {
    return lm_conf_voice_SetAgcStatus(c_object_, enabled ? 1 : 0, mode);
}

- (int)setAecmMode:(enum LMAecmModes)mode
         enableCNG:(BOOL)enableCNG {
    return lm_conf_voice_SetAecmMode(c_object_, mode, enableCNG ? 1 : 0);
}


- (int)setVADStatus:(BOOL)enabled
               mode:(enum LMVadModes)mode
         disableDTX:(BOOL)disableDTX {
    return lm_conf_voice_SetVADStatus(c_object_, enabled ? 1 : 0, mode, disableDTX ? 1 : 0);
}


- (int)getLoudspeakerStatus:(BOOL *)enabled {
    int v = 0;
    int ret = lm_conf_voice_GetLoudspeakerStatus(c_object_, &v);
    *enabled = !!v;
    return ret;
}

- (int)getEcStatus:(BOOL *)enabled
              mode:(enum LMEcModes *)mode {
    int v = 0;
    int ret = lm_conf_voice_GetEcStatus(c_object_, &v, (int*)(mode));
    *enabled = !!v;
    return ret;
}

- (int)getNsStatus:(BOOL *)enabled
              mode:(enum LMNsModes *)mode {
    int v = 0;
    int ret = lm_conf_voice_GetNsStatus(c_object_, &v, (int*)(mode));
    *enabled = !!v;
    return ret;
}


- (int)getAgcStatus:(BOOL *)enabled
               mode:(enum LMAgcModes *)mode {
    int v = 0;
    int ret = lm_conf_voice_GetAgcStatus(c_object_, &v, (int*)(mode));
    *enabled = !!v;
    return ret;
}


- (int)getAecmMode:(enum LMAecmModes *)mode
        enabledCNG:(BOOL *)enabledCNG {
    int v = 0;
    int ret = lm_conf_voice_GetAecmMode(c_object_, (int*)(mode), &v);
    *enabledCNG = !!v;
    return ret;
}


- (int)getVADStatus:(BOOL *)enabled
               mode:(enum LMVadModes *)mode
        disabledDTX:(BOOL *)disabledDTX {
    int v = 0;
    int v1 = 0;
    int ret = lm_conf_voice_GetVADStatus(c_object_, &v, (int*)(mode), &v1);
    *enabled = !!v;
    *disabledDTX = !!v1;
    return ret;
}

- (int)enableDriftCompensation:(BOOL)enabled {
    return lm_conf_voice_EnableDriftCompensation(c_object_, enabled ? 1 : 0);
}

- (int)driftCompensationEnabled:(BOOL *)enabled {
    int v = 0;
    int ret = lm_conf_voice_DriftCompensationEnabled(c_object_, &v);
    *enabled = !!v;
    return ret;
}

- (int)setDelayOffsetMs:(int)offset {
    return lm_conf_voice_SetDelayOffsetMs(c_object_, offset);
}

- (int)delayOffsetMs:(int *)offset {
    return lm_conf_voice_DelayOffsetMs(c_object_, offset);
}

- (int)enableHighPassFilter:(BOOL)enabled {
    return lm_conf_voice_EnableHighPassFilter(c_object_, enabled ? 1 : 0);
}

- (int)isHighPassFilterEnabled:(BOOL *)enabled {
    int v = 0;
    int ret = lm_conf_voice_IsHighPassFilterEnabled(c_object_, &v);
    *enabled = !!v;
    return ret;
}

- (int)enableInput:(BOOL)enabled {
    return lm_conf_voice_EnableInput(c_object_, enabled ? 1 : 0);
}

- (int)enableOutput:(BOOL)enabled {
    return lm_conf_voice_EnableOutput(c_object_, enabled ? 1 : 0);
}

- (int)getInputState:(BOOL *)enabled {
    int v = 0;
    int ret = lm_conf_voice_GetInputState(c_object_, &v);
    *enabled = !!v;
    return ret;
}

- (int)getOutputState:(BOOL *)enabled {
    int v = 0;
    int ret = lm_conf_voice_GetOutputState(c_object_, &v);
    *enabled = !!v;
    return ret;
}

- (int)disablePlaybackInput:(BOOL)disabled {
    return lm_conf_voice_DisablePlaybackInput(c_object_, disabled ? 1 : 0);
}

- (int)disableIPCameraInput:(BOOL)disabled {
    return lm_conf_voice_DisableIPCameraInput(c_object_, disabled ? 1 : 0);
}

- (int)disableMediaPlayerInput:(BOOL)disabled {
    return lm_conf_voice_DisableMediaPlayerInput(c_object_, disabled ? 1 : 0);
}

- (int)disableExternalDeviceInput:(BOOL)disabled {
    return lm_conf_voice_DisableExternalDeviceInput(c_object_, disabled ? 1 : 0);
}

- (int)disablePlaybackInputLocalOutput:(BOOL)disabled {
    return lm_conf_voice_DisablePlaybackInputLocalOutput(c_object_, disabled ? 1 : 0);
}

- (int)disableIPCameraInputLocalOutput:(BOOL)disabled {
    return lm_conf_voice_DisableIPCameraInputLocalOutput(c_object_, disabled ? 1 : 0);
}

- (int)disableMediaPlayerInputLocalOutput:(BOOL)disabled {
    return lm_conf_voice_DisableMediaPlayerInputLocalOutput(c_object_, disabled ? 1 : 0);
}

- (int)disableExternalDeviceInputLocalOutput:(BOOL)disabled {
    return lm_conf_voice_DisableExternalDeviceInputLocalOutput(c_object_, disabled ? 1 : 0);
}

- (int)getDisablePlaybackInputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisablePlaybackInputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

- (int)getDisableIPCameraInputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisableIPCameraInputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

- (int)getDisableMediaPlayerInputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisableMediaPlayerInputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

- (int)getDisableExternalDeviceInputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisableExternalDeviceInputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

- (int)getDisablePlaybackInputLocalOutputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisablePlaybackInputLocalOutputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

- (int)getDisableIPCameraInputLocalOutputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisableIPCameraInputLocalOutputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

- (int)getDisableMediaPlayerInputLocalOutputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisableMediaPlayerInputLocalOutputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

- (int)getDisableExternalDeviceInputLocalOutputState:(BOOL *)disabled {
    int v = 0;
    int ret = lm_conf_voice_GetDisableExternalDeviceInputLocalOutputState(c_object_, &v);
    *disabled = !!v;
    return ret;
}

// Playout file locally
- (int)startPlayingFileLocally:(int *)node
                      fileName:(NSString *)fileName
                          loop:(BOOL)loop
                        format:(enum LMVoiceFileFormats)format
                 volumeScaling:(float)volumeScaling
                  startPointMs:(int)startPointMs
                   stopPointMs:(int)stopPointMs {
    return lm_conf_voice_StartPlayingFileLocallyFromFile(c_object_, [fileName UTF8String],
                                                         loop ? 1 : 0, format, volumeScaling, startPointMs, stopPointMs, node);
}

- (int)startPlayingFileLocally:(int *)node
                        stream:(const void *)stream
                        length:(int)stream_len
                        format:(enum LMVoiceFileFormats)format
                 volumeScaling:(float)volumeScaling
                  startPointMs:(int)startPointMs
                   stopPointMs:(int)stopPointMs {
    return lm_conf_voice_StartPlayingFileLocallyFromStream(c_object_, stream,
                                                           stream_len, format, volumeScaling, startPointMs, stopPointMs, node);
}

- (int)stopPlayingFileLocally:(int)node {
    return lm_conf_voice_StopPlayingFileLocallyWithNode(c_object_, node);
}

- (int)isPlayingFileLocally:(int)node {
    return !!lm_conf_voice_IsPlayingFileLocallyWithNode(c_object_, node);
}

// Use file as microphone input
- (int)startPlayingFileAsMicrophone:(NSString *)fileName
                               loop:(BOOL)loop
                  mixWithMicrophone:(BOOL)mixWithMicrophone
                             format:(enum LMVoiceFileFormats)format
                      volumeScaling:(float)volumeScaling {
    return lm_conf_voice_StartPlayingFileAsMicrophoneFromFile(c_object_,
                                                              [fileName UTF8String], loop ? 1 : 0, mixWithMicrophone, format, volumeScaling);
}

- (int)startPlayingFileAsMicrophone:(const void *)stream
                             length:(int)stream_len
                  mixWithMicrophone:(BOOL)mixWithMicrophone
                             format:(enum LMVoiceFileFormats)format
                      volumeScaling:(float)volumeScaling {
    return lm_conf_voice_StartPlayingFileAsMicrophoneFromStream(c_object_,
                                                                stream, stream_len, mixWithMicrophone, format, volumeScaling);
}

- (int)stopPlayingFileAsMicrophone {
    return lm_conf_voice_StopPlayingFileAsMicrophone(c_object_);
}

- (int)isPlayingFileAsMicrophone {
    return !!lm_conf_voice_IsPlayingFileAsMicrophone(c_object_);
}


// Record speaker signal to file
- (int)startRecordingPlayout:(NSString *)account
                    fileName:(NSString *)fileName
                       codec:(enum LMVoiceCodecModes)codec
                maxSizeBytes:(int)maxSizeBytes {
    return lm_conf_voice_StartRecordingAccountPlayoutToFile(c_object_,
                                                            [account UTF8String], [fileName UTF8String], codec, maxSizeBytes);
}


- (int)startRecordingPlayout:(NSString *)account
                      stream:(void *)stream
                      length:(int)stream_len
                       codec:(enum LMVoiceCodecModes)codec {
    return lm_conf_voice_StartRecordingAccountPlayoutToStream(c_object_,
                                                              [account UTF8String], stream, stream_len, codec);
}

- (int)stopRecordingPlayout:(NSString *)account {
    return lm_conf_voice_StopRecordingAccountPlayout(c_object_,	[account UTF8String]);
}

- (int)startRecordingPlayout:(NSString *)fileName
                       codec:(enum LMVoiceCodecModes)codec
                maxSizeBytes:(int)maxSizeBytes {
    return lm_conf_voice_StartRecordingAllPlayoutToFile(c_object_,
                                                        [fileName UTF8String], codec, maxSizeBytes);
}

- (int)startRecordingPlayout:(void *)stream
                      length:(int)stream_len
                       codec:(enum LMVoiceCodecModes)codec {
    return lm_conf_voice_StartRecordingAllPlayoutToStream(c_object_,
                                                          stream, stream_len, codec);
}


- (int)stopRecordingPlayout {
    return lm_conf_voice_StopRecordingAllPlayout(c_object_);
}


// Record microphone signal to file
- (int)startRecordingMicrophone:(NSString *)fileName
                          codec:(enum LMVoiceCodecModes)codec
                   maxSizeBytes:(int)maxSizeBytes {
    return lm_conf_voice_StartRecordingMicrophoneToFile(c_object_, [fileName UTF8String], codec, maxSizeBytes);
}

- (int)startRecordingMicrophone:(void *)stream
                         length:(int)stream_len
                          codec:(enum LMVoiceCodecModes)codec {
    return lm_conf_voice_StartRecordingMicrophoneToStream(c_object_, stream, stream_len, codec);
}

- (int)stopRecordingMicrophone {
    return lm_conf_voice_StopRecordingMicrophone(c_object_);
}

- (int)addIPCamera:(const struct LMIPCameraInfo*)info
           channel:(int)camera_channel {
    return lm_conf_voice_AddIPCamera(c_object_, info, camera_channel);
}

- (int)removeIPCamera:(int)identity
              channel:(int)camera_channel {
    return lm_conf_voice_RemoveIPCamera(c_object_, identity, camera_channel);
}

- (int)addExternalRAWDataInputDevice:(int)sampleRate
                             channel:(int)channel
                            identity:(int)identity {
    return lm_conf_voice_AddExternalRAWDataInputDevice(c_object_, sampleRate, channel, identity);
}

- (int)removeExternalRAWDataInputDevice:(int)identity {
    return lm_conf_voice_RemoveExternalRAWDataInputDevice(c_object_, identity);
}

- (int)incomingExternalInputRAWData:(int)identity
                               data:(const void*)data
                            datalen:(int)data_len {
    return lm_conf_voice_IncomingExternalInputRAWData(c_object_, identity, data, data_len);
}

- (int)addExternalRTPDataInputDevice:(int)identity {
    return lm_conf_voice_AddExternalRTPDataInputDevice(c_object_, identity);
}

- (int)removeExternalRTPDataInputDevice:(int)identity {
    return lm_conf_voice_RemoveExternalRTPDataInputDevice(c_object_, identity);
}

- (int)incomingExternalInputRTPData:(int)identity
                               data:(const void*)data
                            datalen:(int)data_len
                          delayMode:(enum LMVoiceDelayModes)delay_mode {
    return lm_conf_voice_IncomingExternalInputRTPData(c_object_, identity, data, data_len, delay_mode);
}

//	for udp default kVoiceAdaptiveIO, tcp return -1
- (int)setVoiceIOMode:(enum LMVoiceIOModes)mode {
    return lm_conf_voice_SetVoiceIOMode(c_object_, mode);
}

- (int)getVoiceIOMode:(enum LMVoiceIOModes *)mode {
    return lm_conf_voice_GetVoiceIOMode(c_object_, (int*)(mode));
}



@end
